home *** CD-ROM | disk | FTP | other *** search
/ Practical Algorithms for Image Analysis / Practical Algorithms for Image Analysis.iso / TARFILE.GZ / tarfile / ch_4.3 / contour / contour.c < prev    next >
C/C++ Source or Header  |  1999-09-11  |  10KB  |  345 lines

  1. /* 
  2.  * contour.c
  3.  * 
  4.  * Practical Algorithms for Image Analysis
  5.  * 
  6.  * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
  7.  */
  8.  
  9. /* CONTOUR:     program determines contour boundaries for binary image
  10.  *                    usage: contour infile.img outfile.img
  11.  *
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include "tiffimage.h"          /* picfile info on images */
  18. #include "images.h"
  19. extern void print_sos_lic ();
  20.  
  21. #define ON 0                    /* binarization values */
  22. #define OFF 255
  23. #define ONM1 1
  24. #define CONTOUR 32              /* value of contour pixel */
  25. #define CENTROID 31             /* value of centroid location pixel */
  26. #define MAX_CONTOUR 10000       /* maximum length of contour */
  27. #define DISPLAY_FLAG_DFLT 0     /* =0 contours; =1 centroids; =2 both */
  28.  
  29. #define SQUARE(IMG,X,Y)    IMG[Y][X] = ONM1, IMG[Y-1][X-1] = ONM1,\
  30.                IMG[Y-1][X] = ONM1, IMG[Y-1][X+1] = ONM1,\
  31.                IMG[Y][X+1] = ONM1, IMG[Y+1][X+1] = ONM1,\
  32.                IMG[Y+1][X] = ONM1, IMG[Y+1][X-1] = ONM1,\
  33.                IMG[Y][X-1] = ONM1
  34.  
  35. int nextcntr (unsigned char **, long *, long *, long *);
  36. long usage (short);
  37. long input (int, char **, long *, short *, short *);
  38.  
  39. main (argc, argv)
  40.      int argc;
  41.      char *argv[];
  42. {
  43.   Image *imgIO;                 /* I/O image structure */
  44.   unsigned char **image;        /* input/output image */
  45.   long height, width;           /* size of I/O images */
  46.   long xEndM1, yEndM1;          /* end of rows/columns minus one */
  47.   struct cntr {                 /* structure for each contour pt */
  48.     long x, y;                  /* location */
  49.     long iDirn;                 /* chain code direction */
  50.     long curve;                 /* local curvature */
  51.   } *cntr;
  52.   long maxContour;              /* max. contour length (for memory alloc.) */
  53.   short displayFlag;            /* =0 contours; =1 centroids; =2 both */
  54.   short printFlag;              /* =1 print contour info; =0 don't */
  55.   long nContour;                /* number of contours */
  56.   long lContour;                /* length of contour */
  57.   long maxLContour;             /* max. length of contour */
  58.   long lContourSum;             /* sum of contour lengths */
  59.   double xCentroid, yCentroid;  /* x,y centroid location for contour */
  60.   long xStart, yStart;          /* starting pixels of contour */
  61.   long iDirn;                   /* direction coming into contour */
  62.   long x, y;
  63.   long temp;
  64.  
  65. /* user input */
  66.   if (input (argc, argv, &maxContour, &displayFlag, &printFlag) < 0)
  67.     return (-1);
  68.  
  69.   imgIO = ImageIn (argv[1]);
  70.   image = imgIO->img;
  71.   height = ImageGetHeight (imgIO);
  72.   width = ImageGetWidth (imgIO);
  73.   printf ("image size is %dx%d\n", width, height);
  74.  
  75. /* allocate contour memory */
  76.   if ((cntr = (struct cntr *) calloc (maxContour, sizeof (struct cntr)))
  77.       == NULL) {
  78.     printf ("CONTOUR: not enough memory -- sorry.\n");
  79.     return (-1);
  80.   }
  81.  
  82. /* determine contours */
  83.   yEndM1 = height - 1;
  84.   xEndM1 = width - 1;
  85.   nContour = 0;
  86.   maxLContour = 0;
  87.   lContourSum = 0;
  88.   for (y = 1; y < yEndM1; y++) {
  89.     for (x = 1; x < xEndM1; x++) {
  90.       /* when find ON-pixel, trace contour */
  91.       if (image[y][x] == ON && image[y][x - 1] == OFF) {
  92.         nContour++;
  93.         iDirn = 2;
  94.         cntr[0].x = xStart = x;
  95.         cntr[0].y = yStart = y;
  96.         xCentroid = (double) x;
  97.         yCentroid = (double) y;
  98.         cntr[0].iDirn = iDirn;
  99.         cntr[0].curve = 0;
  100.         lContour = 1;
  101.         do {
  102.           image[y][x] = CONTOUR;
  103.           nextcntr (image, &x, &y, &iDirn);
  104.           cntr[lContour].x = x;
  105.           cntr[lContour].y = y;
  106.           cntr[lContour].iDirn = iDirn;
  107.           xCentroid += (double) x;
  108.           yCentroid += (double) y;
  109.           temp = iDirn - cntr[lContour - 1].iDirn;
  110.           if (temp > 4)
  111.             temp -= 8;
  112.           else if (temp < -4)
  113.             temp += 8;
  114.           cntr[lContour].curve = temp;
  115.           lContour++;
  116.           if (lContour == MAX_CONTOUR) {
  117.             printf ("Nuts -- maximum contour length reached = %d\n", lContour);
  118.             return (-1);
  119.           }
  120.         } while (!(x == xStart && y == yStart));
  121.         if (lContour > maxLContour)
  122.           maxLContour = lContour;
  123.         xCentroid = xCentroid / (double) lContour;
  124.         yCentroid = yCentroid / (double) lContour;
  125.         lContourSum += lContour;
  126.         if (displayFlag > 0)
  127.           image[(long) (yCentroid + 0.5)][(long) (xCentroid + 0.5)] = CENTROID;
  128.         if (printFlag != 0)
  129.           printf ("contour %ld: length = %ld, centroid = (%5.2f,%5.2f)\n",
  130.                   nContour - 1, lContour, xCentroid, yCentroid);
  131.       }
  132.     }
  133.   }
  134.  
  135.   switch (displayFlag) {
  136.   case 0:
  137.     for (y = 0; y < height; y++)
  138.       for (x = 0; x < width; x++)
  139.         image[y][x] = (image[y][x] == CONTOUR) ? ON : OFF;
  140.     break;
  141.   case 1:
  142.     for (y = 0; y < height; y++)
  143.       for (x = 0; x < width; x++) {
  144.         if (image[y][x] == CENTROID)
  145.           SQUARE (image, x, y);
  146.         else if (image[y][x] == ONM1);
  147.         else
  148.           image[y][x] = OFF;
  149.       }
  150.     break;
  151.   case 2:
  152.     for (y = 0; y < height; y++)
  153.       for (x = 0; x < width; x++) {
  154.         if (image[y][x] == CENTROID)
  155.           SQUARE (image, x, y);
  156.         else if (image[y][x] == CONTOUR)
  157.           image[y][x] = ON;
  158.         else if (image[y][x] == ONM1);
  159.         else
  160.           image[y][x] = OFF;
  161.       }
  162.     break;
  163.   default:
  164.     for (y = 0; y < height; y++)
  165.       for (x = 0; x < width; x++)
  166.         image[y][x] = (image[y][x] == CONTOUR) ? ONM1 : OFF;
  167.   }
  168.  
  169.   if (nContour == 0)
  170.     printf ("no image regions\n");
  171.   else
  172.     printf ("no. contours = %d, max length = %d, avg. length = %d\n",
  173.             nContour, maxLContour, lContourSum / nContour);
  174.  
  175.   ImageOut (argv[2], imgIO);
  176.  
  177.   return (0);
  178. }
  179.  
  180.  
  181.  
  182. /* NEXTCNTR:    function examines neighborhood for next contour pixel
  183.  */
  184.  
  185. int
  186. nextcntr (image, x, y, iDirn)
  187.      unsigned char **image;
  188.      long *x, *y;               /* temporary x and y storage for trace */
  189.      long *iDirn;               /* direction from last pixel on contour */
  190. {
  191.   long ring[16];                /* neighborhood ring of pixels */
  192.   long i, j;
  193.  
  194. /* find neighborhood ring of pixels */
  195.   ring[0] = ring[8] = image[*y - 1][*x];
  196.   ring[1] = ring[9] = image[*y - 1][*x + 1];
  197.   ring[2] = ring[10] = image[*y][*x + 1];
  198.   ring[3] = ring[11] = image[*y + 1][*x + 1];
  199.   ring[4] = ring[12] = image[*y + 1][*x];
  200.   ring[5] = ring[13] = image[*y + 1][*x - 1];
  201.   ring[6] = ring[14] = image[*y][*x - 1];
  202.   ring[7] = ring[15] = image[*y - 1][*x - 1];
  203.  
  204.   i = (*iDirn + 4 + 1) % 8;
  205.  
  206.   for (j = 0; j < 8; j++, i++)
  207.     if (ring[i] != OFF && ring[i - 1] == OFF)
  208.       break;
  209.  
  210.   if (j == 8)
  211.     return (0);                 /* isolated pixel */
  212.  
  213.   *iDirn = i % 8;
  214.  
  215.   switch (i) {
  216.   case 1:
  217.   case 9:
  218.     *x = *x + 1;
  219.     *y = *y - 1;
  220.     break;
  221.   case 2:
  222.   case 10:
  223.     *x = *x + 1;
  224.     break;
  225.   case 3:
  226.   case 11:
  227.     *x = *x + 1;
  228.     *y = *y + 1;
  229.     break;
  230.   case 4:
  231.   case 12:
  232.     *y = *y + 1;
  233.     break;
  234.   case 5:
  235.   case 13:
  236.     *x = *x - 1;
  237.     *y = *y + 1;
  238.     break;
  239.   case 6:
  240.   case 14:
  241.     *x = *x - 1;
  242.     break;
  243.   case 7:
  244.   case 15:
  245.     *x = *x - 1;
  246.     *y = *y - 1;
  247.     break;
  248.   case 8:
  249.   case 0:
  250.     *y = *y - 1;
  251.     break;
  252.   default:;
  253.   }
  254.  
  255.   return (0);
  256. }
  257.  
  258.  
  259.  
  260.  
  261. /* USAGE:       function gives instructions on usage of program
  262.  *                    usage: usage (flag)
  263.  *              When flag is 1, the long message is given, 0 gives short.
  264.  */
  265.  
  266. long
  267. usage (flag)
  268.      short flag;                /* flag =1 for long message; =0 for short message */
  269. {
  270.  
  271. /* print short usage message or long */
  272.   printf ("USAGE: contour inimg outimg [-d DISPLAY] [-p] \n");
  273.   printf ("                            [-m MAX_CONTOUR_LENGTH] [-L]\n");
  274.   if (flag == 0)
  275.     return (-1);
  276.  
  277.   printf ("\ncontour identifies contours, or boundaries, of regions\n");
  278.   printf ("in a binary image, and determines features of the regions.\n\n");
  279.   printf ("ARGUMENTS:\n");
  280.   printf ("    inimg: input image filename (TIF)\n");
  281.   printf ("   outimg: output image filename (TIF)\n\n");
  282.   printf ("OPTIONS:\n");
  283.   printf ("            -d DISPLAY: display just centroids (1), or both\n");
  284.   printf ("                        contours and centroids (2);\n");
  285.   printf ("                        default displays just contours.\n");
  286.   printf ("                    -p: PRINT DATA FLAG if set, prints contour\n");
  287.   printf ("                        number, length, and centroid data.\n");
  288.   printf (" -m MAX_CONTOUR_LENGTH: maximum contour length in pixel\n");
  289.   printf ("                        connections. (Default = %d)\n", MAX_CONTOUR);
  290.   printf ("                    -L: print Software License for this module\n");
  291.  
  292.   return (-1);
  293. }
  294.  
  295.  
  296. /* INPUT:       function reads input parameters
  297.  *                  usage: input (argc, argv, &maxContour, &displayFlag)
  298.  */
  299.  
  300. #define USAGE_EXIT(VALUE) {usage (VALUE); return (-1);}
  301.  
  302. long
  303. input (argc, argv, maxContour, displayFlag, printFlag)
  304.      int argc;
  305.      char *argv[];
  306.      long *maxContour;          /* maximum contour length (for memory alloc) */
  307.      short *displayFlag;        /* =0 contours; =1 centroids; =2 both */
  308.      short *printFlag;          /* =1, print contour data; =0 don't */
  309. {
  310.   long n;
  311.  
  312.   if (argc == 1)
  313.     USAGE_EXIT (1);
  314.   if (argc == 2)
  315.     USAGE_EXIT (0);
  316.  
  317.   *maxContour = MAX_CONTOUR;
  318.   *displayFlag = DISPLAY_FLAG_DFLT;
  319.   *printFlag = 0;
  320.  
  321.   for (n = 3; n < argc; n++) {
  322.     if (strcmp (argv[n], "-m") == 0) {
  323.       if (++n == argc || argv[n][0] == '-')
  324.         USAGE_EXIT (0);
  325.       *maxContour = atol (argv[n]);
  326.     }
  327.     else if (strcmp (argv[n], "-d") == 0) {
  328.       if (++n == argc || argv[n][0] == '-')
  329.         USAGE_EXIT (0);
  330.       *displayFlag = (short) atol (argv[n]);
  331.     }
  332.     else if (strcmp (argv[n], "-p") == 0) {
  333.       *printFlag = 1;
  334.     }
  335.     else if (strcmp (argv[n], "-L") == 0) {
  336.       print_sos_lic ();
  337.       exit (0);
  338.     }
  339.     else
  340.       USAGE_EXIT (0);
  341.   }
  342.  
  343.   return (0);
  344. }
  345.